/*
 * Copyright (c) 2024 iSoftStone Education Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string.h>
#include "lz_hardware.h"

#include <stdio.h>
#include <stdbool.h>
#include "oc_mqtt.h"
#include <cJSON.h>

#include "los_task.h"
#include "ohos_init.h"
#include "cmsis_os.h"
#include "config_network.h"

#include "smart_security.h"
#include "su_03t.h"

#include "iot_adc.h"
#include "iot_errno.h"
#include "mpu6050.h"
#include "iot_gpio.h"



#define ROUTE_SSID "福建信息职业技术学校"
#define ROUTE_PASSWORD "物联网与人工智能学院"

#define CLIENT_ID "MQTT-客户端ID"
#define USERNAME "MQTT-用户名"
#define PASSWORD "MQTT-密码"

#define MSG_QUEUE_LENGTH 16
#define BUFFER_LEN 50



typedef struct
{
    double illumination; // 亮度
    double temperature;  // 温度
    double humidity;     // 湿度
    double ppm;          // 可燃浓度
    bool ispeople;       // 蜂鸣器
    mpu6050_Data mpu6050;
    int isfire;

} aiguo_huawei_iot_data;

typedef struct
{
    en_msg_type_t msg_type;
    cmd_t cmd;
    aiguo_huawei_iot_data report;
} ia_msg_t;

typedef struct
{
    
    bool led;//rgb
    bool motor;//马达
    bool mg90;//舵机
    bool beep;//蜂鸣器
    bool redled;//报警灯 alarm_light_set_gpio
} ia_status_t;

static unsigned int m_ia_MsgQueue;
static ia_status_t m_app_status;

static unsigned int m_msg_queue;
unsigned int m_su03_msg_queue;


bool led_state = false;
bool mortor_state = false;
bool mg90_state = false;



/***************************************************************
 * 函数名称: ia_deal_report_msg
 * 说    明: 上报智慧农业模块数据到华为云上
 * 参    数: report：智慧农业上报消息指针
 * 返 回 值: 无
 ***************************************************************/

void ia_deal_report_msg(aiguo_huawei_iot_data *report)
{
    char buffer[50];  // 确保缓冲区足够大
    
    oc_mqtt_profile_service_t service;
    oc_mqtt_profile_kv_t temperature;
    oc_mqtt_profile_kv_t humidity;
    oc_mqtt_profile_kv_t luminance;
    oc_mqtt_profile_kv_t ppm;
    oc_mqtt_profile_kv_t PEOPLE;
    oc_mqtt_profile_kv_t led;
    oc_mqtt_profile_kv_t motor;
    oc_mqtt_profile_kv_t mpu6050X;
    oc_mqtt_profile_kv_t mpu6050Y;
    oc_mqtt_profile_kv_t mpu6050Z;
    oc_mqtt_profile_kv_t redled;
    oc_mqtt_profile_kv_t mg90;

    oc_mqtt_profile_kv_t isfire;

    service.event_time = NULL;
    service.service_id = "kjz01";
    service.service_property = &temperature;
    service.nxt = NULL;

    temperature.key = "温度";
    temperature.value = &report->temperature;
    temperature.type = EN_OC_MQTT_PROFILE_VALUE_FLOAT;
    temperature.nxt = &humidity;

    humidity.key = "湿度";
    humidity.value = &report->humidity;
    humidity.type = EN_OC_MQTT_PROFILE_VALUE_FLOAT;
    humidity.nxt = &luminance;

    luminance.key = "亮度";
    luminance.value = &report->illumination;
    luminance.type = EN_OC_MQTT_PROFILE_VALUE_FLOAT;
    luminance.nxt = &ppm;

    ppm.key = "可燃气体";
    ppm.value = &report->ppm;
    ppm.type = EN_OC_MQTT_PROFILE_VALUE_FLOAT;
    ppm.nxt = &mpu6050X;
    

    mpu6050X.key = "加速度X";
    char x[10];
    snprintf(x, sizeof(x), "%hd", report->mpu6050.x);
    mpu6050X.value = x;
    mpu6050X.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    mpu6050X.nxt = &mpu6050Y;

    mpu6050Y.key = "加速度Y";
    char y[10];
    snprintf(y, sizeof(y), "%hd",report->mpu6050.y);
    mpu6050Y.value =  y;
    mpu6050Y.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    mpu6050Y.nxt = &mpu6050Z;



    mpu6050Z.key = "加速度Z";
    char z[10];
    snprintf(z, sizeof(z), "%hd", report->mpu6050.z);
    mpu6050Z.value = z;
    mpu6050Z.type =  EN_OC_MQTT_PROFILE_VALUE_STRING;
    mpu6050Z.nxt =&PEOPLE;


    PEOPLE.key = "是否有人";
    PEOPLE.value = (int)report->ispeople==1?"有人":"没人";
    PEOPLE.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    PEOPLE.nxt =&led;



    led.key = "RGB灯状态";
    led.value = m_app_status.led==true ? "开" : "关";
    led.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    led.nxt = &motor;

    motor.key = "电机状态";
    motor.value = m_app_status.motor==true ? "开" : "关";
    motor.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    motor.nxt = &redled;

    redled.key = "报警灯状态";
    redled.value = m_app_status.redled==true ? "开" : "关";
    redled.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    redled.nxt = &mg90;

    mg90.key = "舵机状态";
    mg90.value = m_app_status.redled==true ? "开" : "关";
    mg90.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    mg90.nxt = &isfire;
    



    isfire.key = "火焰";
    isfire.value =report->isfire ==0 ? "有" : "无";
    isfire.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    isfire.nxt = NULL;


    int ret = oc_mqtt_profile_propertyreport(USERNAME, &service);
    printf("上报状态码Code:%d",ret);

}

/***************************************************************
 * 函数名称: ia_deal_cmd_msg
 * 说    明: 处理华为云下发的命令
 * 参    数: cmd：华为云下发的命令结构体指针
 * 返 回 值: 无
 ***************************************************************/
void ia_deal_cmd_msg(cmd_t *cmd)
{
    cJSON *obj_root;
    cJSON *obj_cmdname;
    cJSON *obj_paras;
    cJSON *obj_para;
    int cmdret = 1;
    oc_mqtt_profile_cmdresp_t cmdresp;

    obj_root = cJSON_Parse(cmd->payload);
    if (obj_root == NULL)
    {
        goto EXIT_JSONPARSE;
    }

    obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
    if (obj_cmdname == NULL)
    {
        goto EXIT;
    }
    if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "RGB控制"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "paras");
        if (obj_paras == NULL)
        {
            goto EXIT;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "open");
        if (obj_para == NULL)
        {
            goto EXIT;
        }
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            m_app_status.led = 1;
            led_state = m_app_status.led;
            light_set_state(true);

            printf("Light On\n");
        }
        else
        {
            m_app_status.led = 0;
            led_state = m_app_status.led;
            light_set_state(false);

            printf("Light Off\n");
        }
        cmdret = 0;
    }
    else if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "电机控制"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
        if (obj_paras == NULL)
        {
            goto EXIT;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "open");
        if (obj_para == NULL)
        {
            goto EXIT;
        }
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            m_app_status.motor = 1;
            mortor_state = m_app_status.motor;
            motor_set_state(true);
            printf("Motor On\n");
        }
        else
        {
            m_app_status.motor = 0;
             mortor_state = m_app_status.motor;
            motor_set_state(false);
            printf("Motor Off\n");
        }
        cmdret = 0;
    }
    ////////////////////////////////////////////////////////////////////
    else if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "舵机控制"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
        if (obj_paras == NULL)
        {
            goto EXIT;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "open");
        if (obj_para == NULL)
        {
            goto EXIT;
        }
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            m_app_status.mg90 = 1;
            mg90_state = m_app_status.mg90;
            mg_open();

            printf("mg90 On\n");
        }
        else
        {
            m_app_status.mg90 = 0;
            mg90_state = m_app_status.mg90;
            mg_close();
            printf("mg90 Off\n");
        }
        cmdret = 0;
    }

    else if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "蜂鸣器控制"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
        if (obj_paras == NULL)
        {
            goto EXIT;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "open");
        if (obj_para == NULL)
        {
            goto EXIT;
        }
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            m_app_status.beep = 1;
            beep_set_state(true);

            printf("beep On\n");
        }
        else
        {
            m_app_status.beep = 0;
            beep_set_state(false);
            
            printf("beep Off\n");
        }
        cmdret = 0;
    }
        else if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "报警灯控制"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
        if (obj_paras == NULL)
        {
            goto EXIT;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "open");
        if (obj_para == NULL)
        {
            goto EXIT;
        }
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            m_app_status.redled = 1;
            alarm_light_set_gpio(true);
            beep_set_state(true);
            printf("beep On\n");
        }
        else
        {
            m_app_status.redled = 0;
            alarm_light_set_gpio(false);
            beep_set_state(false);
            printf("beep Off\n");
        }
        cmdret = 0;
    }


EXIT:
    cJSON_Delete(obj_root);
EXIT_JSONPARSE:
    cmdresp.paras = NULL;
    cmdresp.request_id = cmd->request_id;
    cmdresp.ret_code = cmdret;
    cmdresp.ret_name = NULL;

    oc_mqtt_profile_cmdresp(NULL, &cmdresp);
}

/***************************************************************
 * 函数名称: ia_cmd_response_callback
 * 说    明: 华为云命令处理回调函数
 * 参    数: recv_data：接收的数据指针
 *           recv_size：接收数据的大小
 *           resp_data：响应数据的指针
 *           resp_size：响应数据的大小
 * 返 回 值: 无
 ***************************************************************/
void ia_cmd_response_callback(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size)
{
    ia_msg_t *app_msg = NULL;
    int ret = 0;

    app_msg = malloc(sizeof(ia_msg_t));
    if (app_msg == NULL)
    {
        printf("malloc msg fail");
        return;
    }
    app_msg->msg_type = en_msg_cmd;
    app_msg->cmd.payload = (char *)recv_data;

    printf("recv data is %.*s", recv_size, recv_data);
    if (LOS_OK != LOS_QueueWrite(m_msg_queue, (void *)app_msg, sizeof(ia_msg_t), 0))
    {
        printf("%s LOS_QueueWrite fail\n", __func__);
        free(recv_data);
        free(app_msg);
    }
    *resp_data = NULL;
    *resp_size = 0;
}



void smart_security_thread(void *arg)
{
    uint8_t hwaddr[6] = {0x10, 0xdc, 0xb6, 0x90, 0x00, 0x00};
    ia_msg_t *data_ptr = NULL;
    unsigned int addr;
    int ret;
    FlashInit();
    VendorSet(VENDOR_ID_MAC, hwaddr, 6); // 多人同时做该实验，请修改各自不同的WiFi MAC地址
    VendorSet(VENDOR_ID_WIFI_ROUTE_SSID, ROUTE_SSID, sizeof(ROUTE_SSID));
    VendorSet(VENDOR_ID_WIFI_ROUTE_PASSWD, ROUTE_PASSWORD, sizeof(ROUTE_PASSWORD));
   //printf("%s%s",ROUTE_SSID,ROUTE_PASSWORD);
    SetWifiModeOn();


    device_info_init(CLIENT_ID, USERNAME, PASSWORD);
    ret = oc_mqtt_init();
    if (ret != LOS_OK)
    {
        printf("oc_mqtt_init fail ret:%d\n", ret);
    }
    oc_set_cmd_rsp_cb(ia_cmd_response_callback);
    

    while (1)
    {
        

        ret = LOS_QueueRead(m_msg_queue, (void *)&addr, BUFFER_LEN, LOS_WAIT_FOREVER);
       

        if (ret == LOS_OK)
        {
            data_ptr = addr;
            switch (data_ptr->msg_type)
            {
                case en_msg_cmd:
                    ia_deal_cmd_msg(&data_ptr->cmd);
         
                    break;
                case en_msg_report:
                    ia_deal_report_msg(&data_ptr->report);

                    break;
                default:
                    break;
            }

            free(data_ptr);
            data_ptr = NULL;
        }
        else
        {
            LOS_Msleep(100);
        }

   


       
    }
}

void device_read_thraed(void *arg)
{
   
    su03t_init();
    mq2_init();//烟雾
    body_induction_dev_init();//人体
    i2c_dev_init();   // 温湿度
    motor_dev_init(); // 电机
    light_dev_init(); // RGB
    init_sg90();//舵机
    beep_dev_init();    // 蜂鸣器
    alarm_light_init(); // 报警灯
    lcd_dev_init();     // LCD
    lcd_load_ui();//LCDui
    mpu6050_init();

    

    IoTGpioInit(GPIO0_PB7);
    IoTGpioSetDir(GPIO0_PB7, IOT_GPIO_DIR_IN);

   PinctrlSet(GPIO0_PB7, MUX_FUNC0, PULL_KEEP, DRIVE_LEVEL0);


    ia_msg_t *app_msg = NULL;
    aiguo_huawei_iot_data sensor_data;
    int isfire=0;
   int isfire1=0;
   while (1)
    {

        m_app_status.led=led_state;
        m_app_status.motor=mortor_state;
        m_app_status.mg90=mg90_state;
        
        mpu6050_read_data(&sensor_data.mpu6050);//加速度
        mq2_read_data(&sensor_data.ppm);                         // 烟雾
        body_induction_get_state((bool *)&sensor_data.ispeople); // 人体
        sht30_read_data(&sensor_data.temperature, &sensor_data.humidity);//温湿度
        bh1750_read_data(&sensor_data.illumination);//光照
        IoTGpioGetInputVal(GPIO0_PB7,&isfire);
        IoTGpioGetOutputVal(GPIO0_PB7,&isfire1);
       // printf("火焰%d %d\n",isfire,isfire1);
       
        lcd_set_ppm(sensor_data.ppm);//烟雾
        lcd_set_temperature(sensor_data.temperature);//温度
        lcd_set_humidity(sensor_data.humidity);//湿度
        lcd_set_illumination(sensor_data.illumination);//光照
        lcd_set_body_induction((bool)sensor_data.ispeople);//人体
        lcd_set_SpeedX(sensor_data.mpu6050.x);
        lcd_set_SpeedY(sensor_data.mpu6050.y);
        lcd_set_SpeedZ(sensor_data.mpu6050.z);
        lcd_set_beep_state(m_app_status.redled);
        lcd_set_redled_state(m_app_status.redled);
        lcd_set_mortor_state(m_app_status.motor);
        lcd_set_mg90_state(m_app_status.mg90);
        lcd_set_RGB_state(m_app_status.led);


        app_msg = malloc(sizeof(ia_msg_t));
        if (app_msg != NULL)
        {
            app_msg->msg_type = en_msg_report;
            app_msg->report.ppm = sensor_data.ppm;
            app_msg->report.humidity = sensor_data.humidity;
            app_msg->report.illumination = sensor_data.illumination;
            app_msg->report.temperature =sensor_data.temperature;
            app_msg->report.ispeople = (bool)sensor_data.ispeople;
            app_msg->report.mpu6050 = sensor_data.mpu6050;
            app_msg->report.isfire = isfire;
  
            if (LOS_QueueWrite(m_msg_queue, (void *)app_msg, sizeof(ia_msg_t), LOS_WAIT_FOREVER) != LOS_OK )
            {
                printf("%s LOS_QueueWrite fail\n", __func__);
                free(app_msg);
            }


             LOS_Msleep(100);
         }
    }
}


/***************************************************************
 * 函数名称: smart_security_example
 * 说    明: 开机自启动调用函数
 * 参    数: 无
 * 返 回 值: 无
 ***************************************************************/
void smart_security_example()
{
    unsigned int thread_id_1;
    unsigned int thread_id_2;
    unsigned int thread_id_3;
    TSK_INIT_PARAM_S task_1 = {0};
    TSK_INIT_PARAM_S task_2 = {0};
    TSK_INIT_PARAM_S task_3 = {0};
    unsigned int ret = LOS_OK;
    ret = LOS_QueueCreate("queue", MSG_QUEUE_LENGTH, &m_msg_queue, 0, BUFFER_LEN);
    if (ret != LOS_OK)
    {
        printf("Falied to create Message Queue ret:0x%x\n", ret);
        return;
    }

    ret = LOS_QueueCreate("su03_queue", MSG_QUEUE_LENGTH, &m_su03_msg_queue, 0, BUFFER_LEN);
    if (ret != LOS_OK)
    {
        printf("Falied to create Message Queue ret:0x%x\n", ret);
        return;
    }

    task_1.pfnTaskEntry = (TSK_ENTRY_FUNC)smart_security_thread;
    task_1.uwStackSize = 10240;
    task_1.pcName = "smart security thread";
    task_1.usTaskPrio = 24;
    ret = LOS_TaskCreate(&thread_id_1, &task_1);
    if (ret != LOS_OK)
    {
        printf("Falied to create task ret:0x%x\n", ret);
        return;
    }


    task_2.pfnTaskEntry = (TSK_ENTRY_FUNC)device_read_thraed;
    task_2.uwStackSize = 2048;
    task_2.pcName = "device read thraed";
    task_2.usTaskPrio = 24;
    ret = LOS_TaskCreate(&thread_id_2, &task_2);
    if (ret != LOS_OK)
    {
        printf("Falied to create task ret:0x%x\n", ret);
        return;
    }

}

APP_FEATURE_INIT(smart_security_example);
